using System;
using System.Threading;
using System.Windows.Forms;
using System.Collections;
using Microsoft.Build.Framework;
using NLog;

/*
 * Copyright (c) 2007-2011, PerformanceDude.com (infoatperformancedude.com), Lex Li (supportatlextm.com), Rami Abughazaleh (rami.abughazalehatgmail.com)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of PerformanceDude.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
namespace PerformanceDude.MSBuildShellExtension.Loggers.ErrorListLogger
{
    public class MSBuildErrorListLogger : ILogger
    {
        #region Logging
        private static readonly Logger logger = LogManager.GetCurrentClassLogger();
        #endregion
        public Semaphore pool;

        #region ILogger Members

        public void Initialize(IEventSource eventSource)
        {
            logger.Debug("MSBuildErrorListLogger initialized by MSBuild");
            if (eventSource == null)
            {
                throw new ArgumentNullException("eventSource");
            }

            pool = new Semaphore(0, 1);

            // Register event handlers
            //eventSource.MessageRaised += new Microsoft.Build.Framework.BuildMessageEventHandler(OnMessage);
            eventSource.WarningRaised += LogBuildWarningEvent;
            eventSource.ErrorRaised += LogBuildErrorEvent;
            eventSource.BuildStarted += OnBuildStarted;
            eventSource.BuildFinished += OnBuildFinished;
            eventSource.ProjectStarted += OnProjectStarted;
            eventSource.ProjectFinished += OnProjectFinished;

            Thread t = new Thread(
              delegate()
              {
                  Application.EnableVisualStyles();
                  Application.SetCompatibleTextRenderingDefault(false);
                  Application.Run(new ErrorListForm(this));
              });
            t.Start();
            pool.WaitOne();
        }

        private string parameters;
        public string Parameters
        {
            get { return parameters; }
            set { parameters = value; }
        }

        public void Shutdown()
        {
        }

        private LoggerVerbosity verbosity;
        public LoggerVerbosity Verbosity
        {
            get { return verbosity; }
            set { verbosity = value; }
        }

        #endregion

        private Stack buildFileStack;
        private void OnProjectStarted(object sender, ProjectStartedEventArgs args)
        {
            #region Logging
            if (logger.IsDebugEnabled)
            {
                logger.Debug("ProjectStarted from MSBuild");
                logger.Debug("Build properties:");
                foreach (DictionaryEntry property in args.Properties)
                {
                    logger.Debug("- " + property.Key + "=" + property.Value);
                }
            }
            #endregion
            buildFileStack.Push(args.ProjectFile);
            if (buildFileStack.Peek() != null && ProjectStarted != null)
            {
                ProjectStarted(buildFileStack.Peek().ToString());
            }
        }

        private void OnProjectFinished(object sender, ProjectFinishedEventArgs e)
        {
            buildFileStack.Pop();
        }

        private void OnBuildStarted(object sender, BuildStartedEventArgs args)
        {
            #region Logging
            logger.Debug("BuildStarted from MSBuild");
            #endregion
            buildFileStack = new Stack();
            if (BuildStarted != null)
            {
                BuildStarted();
            }
        }

        private void OnBuildFinished(object sender, BuildFinishedEventArgs args)
        {
            #region Logging
            logger.Debug("BuildFinished from MSBuild");
            #endregion
            if (BuildFinished != null)
            {
                BuildFinished(args.Succeeded);
            }
        }

/*
        private void OnMessage(object sender, Microsoft.Build.Framework.BuildMessageEventArgs args)
        {
            if (Message != null)
                Message(args.Message);
        }
*/

        private void LogBuildWarningEvent(object sender, BuildWarningEventArgs args)
        {
            #region Logging
            logger.Debug("WarningRaised from MSBuild");
            #endregion
            if (Warning != null)
                Warning(buildFileStack == null ? string.Empty : buildFileStack.Peek().ToString(), args.Message, args.File, args.LineNumber.ToString(), args.ColumnNumber.ToString());
        }

        private void LogBuildErrorEvent(object sender, BuildErrorEventArgs args)
        {
            #region Logging
            logger.Debug("ErrorRaised from MSBuild");
            #endregion
            if (Error != null)
                Error(buildFileStack == null ? string.Empty : buildFileStack.Peek().ToString(), args.Message, args.File, args.LineNumber.ToString(), args.ColumnNumber.ToString());
        }

        //public event MessageEventHandler Message;
        public event ErrorEventHandler Error;
        public event WarningEventHandler Warning;
        public event BuildStartedEventHandler BuildStarted;
        public event BuildFinishedEventHandler BuildFinished;
        public event ProjectStartedEventHandler ProjectStarted;
    }

    public delegate void ErrorEventHandler(string buildFile, string message, string file, string line, string column);

    public delegate void WarningEventHandler(string buildFile, string message, string file, string line, string column);

    public delegate void BuildStartedEventHandler();

    public delegate void BuildFinishedEventHandler(bool succeeded);

    public delegate void MessageEventHandler(string message);

    public delegate void ProjectStartedEventHandler(string project);
}
